import { Repository } from 'typeorm'
import { InjectRepository } from '@nestjs/typeorm'
import { HttpException, Injectable } from '@nestjs/common'

import { PostsEntity } from './entities/posts.entity'
import { UpdatePostDto } from './dto/update-post.dto'
import { CreatePostDto } from './dto/create-post.dto'
import { BadRequestExceptionFn } from '@/util/exceptions'

export interface PostsRo {
  data: PostsEntity[]
  count: number
}

export interface queryParams {
  pageNum: number
  pageSize: number
  [propName: string]: any
}

export interface queryListParams extends PostsRo {
  pageNum: number
  pageSize: number
  [propName: string]: any
}

@Injectable()
export class PostsService {
  constructor(
    @InjectRepository(PostsEntity)
    private readonly Repo: Repository<PostsEntity>,
  ) { }

  async create(post: CreatePostDto): Promise<PostsEntity> {
    // 因为使用了class-transformer，在CreatePostDto类型验证中，已经校验过必填项，所以不需要再做校验
    // if (!title) throw new HttpException('缺少文章标题', 500);

    return await this.Repo.save(post)
  }

  /**
   *
   * @description
   * 1、安全:where("user.a = :a", { a: "xxx" }), 是防止 SQL 注入的参数
   * 不安全：where("user.a = '" + a + "')，因为它使代码容易受到 SQL 注入。
   *
   * 快捷方式：qb.where("user.a = :a").setParameter("a", "xxx")
   *
   * 2、如果你多次使用 .where，你将覆盖所有先前的 WHERE 表达式
   */
  async findAll(query: queryParams): Promise<queryListParams> {
    const qb = this.Repo.createQueryBuilder('post')
    qb.where('1 = 1')
    if (query.title) qb.andWhere('post.title = :title', { title: query.title })
    if (query.author)
      qb.andWhere('post.author = :author', { author: query.author })
    qb.orderBy('post.create_time', 'DESC')

    const count = await qb.getCount()
    const { pageNum = 1, pageSize = 10 } = query

    // 一旦你使用连接或子查询进行更复杂的查询，limit 和 offset 可能无法按你的预期工作。
    // qb.limit(pageSize)
    // qb.offset(pageSize * (pageNum - 1))

    qb.skip(pageSize * (pageNum - 1)).take(pageSize)

    // 从数据库获取多个结果，例如要从数据库获取所有用户,使用getMany()
    const posts = await qb.getMany()
    return { data: posts, pageNum, pageSize, count }
  }

  // 详情
  async findOne(id: number): Promise<PostsEntity> {
    const post = await this.Repo.findOneBy({ id })
    if (!post) throw new HttpException('文章不存在', 500)
    return post
  }

  async updateById(
    id: number,
    post: UpdatePostDto,
  ): Promise<void | PostsEntity> {
    const existPost = await this.Repo.findOneBy({ id })
    if (!existPost) return BadRequestExceptionFn('文章不存在')

    const updatePost = this.Repo.merge(existPost, post)
    return this.Repo.save(updatePost)
  }

  async remove(id: number) {
    const existPost = await this.Repo.findOneBy({ id })
    if (!existPost) throw new HttpException('文章不存在', 500)
    return this.Repo.remove(existPost)
  }
}
